package com.ta.gulimall.cart.service.impl;

import cn.hutool.core.lang.TypeReference;
import com.ta.gulimall.common.utils.CaptureException;
import com.ta.gulimall.common.utils.system.R;
import com.ta.gulimall.common.utils.RedisUtil;
import com.ta.gulimall.cart.component.handler.TempWithUserHandler;
import com.ta.gulimall.cart.constant.CartConstant;
import com.ta.gulimall.cart.feign.ProductFeignService;
import com.ta.gulimall.cart.service.CartService;
import com.ta.gulimall.cart.view.to.UserInfoTo;
import com.ta.gulimall.cart.view.vo.Cart;
import com.ta.gulimall.cart.view.vo.CartItem;
import com.ta.gulimall.cart.view.vo.SkuInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    ProductFeignService productFeignService;
    ThreadLocal<UserInfoTo> threadLocal = TempWithUserHandler.threadLocal;
    @Autowired
    ThreadPoolExecutor poolExecutor;


    @Override
    public void addCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        CompletableFuture<SkuInfoVo> skuInfoFuture = CompletableFuture.supplyAsync(() -> {
            R r = productFeignService.getSkuInfo(skuId);
            CaptureException.taThrow(r);
            return r.getData(SkuInfoVo.class);
        }, poolExecutor);

        CompletableFuture<List<String>> attrListFuture = CompletableFuture.supplyAsync(() -> {
            R skuAttr = productFeignService.getSkuAttr(skuId);
            CaptureException.taThrow(skuAttr);
            return skuAttr.getData(new TypeReference<List<String>>() {
            });
        }, poolExecutor);

        SkuInfoVo skuInfo = skuInfoFuture.get();
        CartItem build = CartItem.builder()
                .skuId(skuId)
                .check(Boolean.TRUE)
                .title(skuInfo.getSkuTitle())
                .image(skuInfo.getSkuDefaultImg())
                .skuAttr(attrListFuture.get())
                .price(skuInfo.getPrice())
                .count(num)
                .build();

        CartItem cartItem = getCartItem(skuId);
        if (cartItem != null) {
            build = cartItem.setCount(cartItem.getCount() + num);
        }

        redisUtil.hset(getCartKey(), skuId.toString(), build);

    }

    @Override
    public CartItem getCartItem(Long skuId) {
        CartItem hget = redisUtil.hget(getCartKey(), skuId.toString(), CartItem.class);
        return hget;
    }

    @Override
    public void cartCount(Long skuId, Integer num) {
        CartItem val = getCartItem(skuId);
        val.setCount(num);

        redisUtil.hset(getCartKey(), skuId.toString(), val);
    }

    @Override
    public void cartSelected(Long skuId, Boolean status) {
        CartItem val = getCartItem(skuId);
        val.setCheck(status);

        redisUtil.hset(getCartKey(), skuId.toString(), val);
    }

    @Override
    public void cartDelete(Long skuId) {
        redisUtil.hdel(getCartKey(), skuId.toString());
    }

    @Override
    public Cart cartList() {
        String userKey = CartConstant.REDIS_KEY_CART + TempWithUserHandler.threadLocal.get().getUserKey();
        if (threadLocal.get().getUserId() != null) {
            Map<String, CartItem> hmget = redisUtil.hmget(userKey, CartItem.class);
            hmget.values().forEach(f -> {
                try {
                    addCart(f.getSkuId(), f.getCount());
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            });

            CompletableFuture.runAsync(() -> {
                redisUtil.del(userKey);
            }, poolExecutor);
        }

        Map<String, CartItem> map = redisUtil.hmget(getCartKey(), CartItem.class);
        return new Cart().setItems(new ArrayList<>(map.values()));
    }

    @Override
    public List<CartItem> checkCart() {
        Cart cart = cartList();
        List<CartItem> collect = cart.getItems().stream().filter(CartItem::getCheck).collect(Collectors.toList());
        return collect;
    }


    public String getCartKey(){
        UserInfoTo userInfoTo = threadLocal.get();
        if (userInfoTo.getUserId() != null) {
            return CartConstant.REDIS_KEY_CART + userInfoTo.getUserId().toString();
        }else{
            return CartConstant.REDIS_KEY_CART + userInfoTo.getUserKey();
        }
    }

}
